﻿// Sequin.Sequences.Recommenders.Rule
//
// (c) 2011 Arthur Pitman
//
// Part of the Sequin Library
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License (Version 2.1) as published by the Free Software Foundation.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License (Version 2.1) along with this library; if not, write to the 
// Free Software Foundation, Inc., 
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
// or see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sequin.Sequences;

namespace Sequin.Sequences.Recommenders
{
	/// <summary>
	/// Base class for crossfold validation testers
	/// </summary>
	public abstract class CrossfoldTester
	{
		/// <summary>
		/// Number of folds
		/// </summary>
		protected int foldCount;

		/// <summary>
		/// Initializes a new instance of the <see cref="CrossfoldTester"/> class
		/// </summary>
		/// <param name="foldCount"></param>
		public CrossfoldTester(int foldCount)
		{
			this.foldCount = foldCount;
		}

		/// <summary>
		/// Conducts tests on a list of <see cref="Sequence"/> instances
		/// </summary>
		/// <param name="sequences">The <see cref="Sequence"/> instances to test </param>
		public void Test(List<Sequence> sequences)
		{	
			for (int fold = 0; fold < foldCount; fold++)
			{
				var learningSequences = new List<Sequence>();
				var testSequences = new List<Sequence>();

				// split the input sequences into the disjoint learning and testing sets
				var count = sequences.Count;
				for (int i = 0; i < count; i++)
				{
					if ((i % foldCount) == fold)
						testSequences.Add(sequences[i]);
					else
						learningSequences.Add(sequences[i]);
				}

				LearnPhase(learningSequences, fold);
				TestPhase(testSequences, fold);				
			}
		}

		/// <summary>
		/// Provides <see cref="Sequence"/> instances to the recommender for learning
		/// </summary>
		/// <param name="learningSequences">The learning <see cref="Sequence"/> instances</param>
		/// <param name="fold">The current fold index</param>
		protected abstract void LearnPhase(List<Sequence> learningSequences, int fold);		

		/// <summary>
		/// Tests a list of <see cref="Sequence"/> instances
		/// </summary>
		/// <param name="testSequences">The testing <see cref="Sequence"/> instances</param>
		/// <param name="fold">The current fold index</param>
		protected abstract void TestPhase(List<Sequence> testSequences, int fold);	
	}
}
